package com.audaque.jadmin.system.shiro;

import java.io.Serializable;

import javax.annotation.PostConstruct;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

import com.audaque.jadmin.system.model.User;
import com.audaque.jadmin.system.service.UserService;

/**
 * @Description :用户登录数据源
 * @FileName: UserRealm.java
 * @Author :WeiHui.Zhang
 * @Data : 2015年10月15日 下午7:12:16
 * @Version:V1.00
 */
public class UserRealm extends AuthorizingRealm {

	@Autowired
	private UserService userService;

	/**
	 * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用.
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		int userId = Integer.parseInt(principals.getPrimaryPrincipal().toString());
		SimpleAuthorizationInfo authorizationInfo = userService.getAccountRolePermission(userId);
		return authorizationInfo;
	}

	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken)
			throws AuthenticationException {
		// 第一种
		// String username = (String) token.getPrincipal();
		// String password = new String((char[]) token.getCredentials());
		// 第二种：利用自定义的用户验证类,得到用户的登录信息;
		UsernamePasswordCaptchaToken token = (UsernamePasswordCaptchaToken) authcToken;

		// 判断步骤：先验证码后数据库查询
		doCaptchaValidate(token);
		User user = userService.findByAccount(token.getUsername());
		// 不用加上doCaptchaValidate的结果，应为他只有一个结果
		if (user != null) {
			// 包装要缓存的信息
			ShiroUser shiroUser = new ShiroUser(user.getUserId(), user.getUserAccount(), user.getUserName());
			// 设置用户session
			Session session = SecurityUtils.getSubject().getSession();
			session.setAttribute("user", user);
			// 密码验证
			return new SimpleAuthenticationInfo(shiroUser, user.getPassword(), getName());
		} else {
			// 用户不存在
			throw new UnknownAccountException();
		}

	}

	/**
	 * 密码验证，这个是自带的验证类
	 */
	// @SuppressWarnings("static-access")
	// @PostConstruct
	// public void initCredentialsMatcher() {
	// HashedCredentialsMatcher matcher = new
	// HashedCredentialsMatcher(userService.HASH_ALGORITHM);
	// matcher.setHashIterations(userService.HASH_INTERATIONS);
	// setCredentialsMatcher(matcher);
	// }

	@PostConstruct
	public void initCredentialsMatcher() {
		setCredentialsMatcher(new CustomCredentialsMatcher());
	}

	// @Override
	// protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection
	// principals) {
	// ShiroUser shiroUser = (ShiroUser) principals.getPrimaryPrincipal();
	// User user = userService.getUser(shiroUser.loginName);
	//
	// //把principals放session中 key=userId value=principals
	// SecurityUtils.getSubject().getSession().setAttribute(String.valueOf(user.getId()),SecurityUtils.getSubject().getPrincipals());
	//
	// SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
	// //赋予角色
	// for(UserRole userRole:user.getUserRoles()){
	// info.addRole(userRole.getRole().getName());
	// }
	// //赋予权限
	// for(Permission
	// permission:permissionService.getPermissions(user.getId())){
	// if(StringUtils.isNotBlank(permission.getPermCode()))
	// info.addStringPermission(permission.getPermCode());
	// }
	//
	// //设置登录次数、时间
	// userService.updateUserLogin(user);
	// return info;
	// }

	/**
	 * 验证码校验
	 * 
	 * @param token
	 * @return boolean
	 */
	protected void doCaptchaValidate(UsernamePasswordCaptchaToken token) {
		String captcha = (String) SecurityUtils.getSubject().getSession()
				.getAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY);
		if (captcha != null && !captcha.equalsIgnoreCase(token.getCaptcha())) {
			throw new CaptchaException("验证码错误！");
		}
	}

	/**
	 * 自定义Authentication对象，使得Subject携带用户的登录名和其他更多信息
	 */
	public static class ShiroUser implements Serializable {

		private static final long serialVersionUID = -1373760761780840081L;
		public Integer id;
		public String account;
		public String userName;

		public ShiroUser() {
			super();
		}

		public ShiroUser(Integer id, String account, String userName) {
			super();
			this.id = id;
			this.account = account;
			this.userName = userName;
		}

		public Integer getId() {
			return id;
		}

		public void setId(Integer id) {
			this.id = id;
		}

		public String getAccount() {
			return account;
		}

		public void setAccount(String account) {
			this.account = account;
		}

		public String getUserName() {
			return userName;
		}

		public void setUserName(String userName) {
			this.userName = userName;
		}

		/**
		 * 本函数输出将作为默认的<shiro:principal/>输出.
		 */
		@Override
		public String toString() {
			return account;
		}

		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result + ((account == null) ? 0 : account.hashCode());
			return result;
		}

		@Override
		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (getClass() != obj.getClass())
				return false;
			ShiroUser other = (ShiroUser) obj;
			if (account == null) {
				if (other.account != null)
					return false;
			} else if (!account.equals(other.account))
				return false;
			return true;
		}

	}

	@Override
	public void clearCachedAuthorizationInfo(PrincipalCollection principals) {
		super.clearCachedAuthorizationInfo(principals);
	}

	@Override
	public void clearCachedAuthenticationInfo(PrincipalCollection principals) {
		super.clearCachedAuthenticationInfo(principals);
	}

	@Override
	public void clearCache(PrincipalCollection principals) {
		super.clearCache(principals);
	}

	public void clearAllCachedAuthorizationInfo() {
		getAuthorizationCache().clear();
	}

	public void clearAllCachedAuthenticationInfo() {
		getAuthenticationCache().clear();
	}

	public void clearAllCache() {
		clearAllCachedAuthenticationInfo();
		clearAllCachedAuthorizationInfo();
	}

}
